<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>虚拟 DOM 理论 Demo</title>
</head>
<body>
  <div id="root"></div>
  <script>
    // 1. h函数：用来创建虚拟节点
    function h(tag, props, children) {
      return {
        tag,
        props,
        children,
      };
    }

    // 2. render函数：虚拟节点转真实DOM
    function render(vnode) {
      if (typeof vnode === "string") {
        return document.createTextNode(vnode);
      }
      const el = document.createElement(vnode.tag);
      // 设置属性
      if (vnode.props) {
        for (let key in vnode.props) {
          el.setAttribute(key, vnode.props[key]);
        }
      }
      // 子节点
      if (Array.isArray(vnode.children)) {
        vnode.children.forEach(child => {
          el.appendChild(render(child));
        });
      } else if (typeof vnode.children === "string") {
        el.appendChild(document.createTextNode(vnode.children));
      }
      return el;
    }

    // 3. patch函数：对比新老VNode，补丁式更新DOM（简化版）
    function patch(parent, newVNode, oldVNode, index = 0) {
      if (!oldVNode) {
        parent.appendChild(render(newVNode));
      } else if (!newVNode) {
        parent.removeChild(parent.childNodes[index]);
      } else if (
        typeof newVNode === "string" ||
        typeof oldVNode === "string"
      ) {
        if (newVNode !== oldVNode) {
          parent.replaceChild(render(newVNode), parent.childNodes[index]);
        }
      } else if (newVNode.tag !== oldVNode.tag) {
        parent.replaceChild(render(newVNode), parent.childNodes[index]);
      } else {
        // patch props（简化，仅覆盖，没有做props的diff）
        const el = parent.childNodes[index];
        if (newVNode.props) {
          for (let key in newVNode.props) {
            el.setAttribute(key, newVNode.props[key]);
          }
        }
        // 只增删，不做复杂复用
        const newLen = newVNode.children ? newVNode.children.length : 0;
        const oldLen = oldVNode.children ? oldVNode.children.length : 0;
        for (let i = 0; i < newLen || i < oldLen; i++) {
          patch(
            el,
            newVNode.children && newVNode.children[i],
            oldVNode.children && oldVNode.children[i],
            i
          );
        }
      }
    }

    // 4. 使用演示
    const vnode1 = h('div', { id: 'app' }, [
      h('h1', null, 'Hello, Virtual DOM!'),
      h('p', { style: 'color:green' }, 'First render')
    ]);

    const vnode2 = h('div', { id: 'app' }, [
      h('h1', null, 'Hello, Virtual DOM!'),
      h('p', { style: 'color:red' }, 'Second render'),
      h('span', null, '新增span节点！')
    ]);

    const container = document.getElementById('root');
    // 首次渲染
    container.appendChild(render(vnode1));
    // 2秒后更新
    setTimeout(() => {
      patch(container, vnode2, vnode1, 0);
    }, 2000);

  </script>
</body>
</html>
